/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package hcmus.fit.master.sevensea.sprite.ship;

import hcmus.fit.master.sevensea.background.Sea;
import hcmus.fit.master.sevensea.core.AbstractSprite;
import hcmus.fit.master.sevensea.core.Constant;
import hcmus.fit.master.sevensea.util.Queue;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import android.graphics.Bitmap;
import android.graphics.Point;

/**
 * 
 * @author hvp
 */
public class BluePirate extends WarShip {
    public static List<List<Bitmap>> Resource;
    public static int NumOfStatus;

    public BluePirate(Sea seamap, int x, int y) {
        super(seamap, x, y);
        setFrames(Resource.get(Status));
        setNbOfFrame(getFrames().size());
        FrameLibrary = Resource;
    }

    public BluePirate(BluePirate pirate) {
        super(pirate);
    }

    public int GetScore() {
        return 90;
    }

    public boolean update() {
        switch (State) {
            case ShipState.Idle:
                break;
            case ShipState.Moving:
                if (FinishMove()) {
                    State = ShipState.Idle;
                    X = (getRealPos().x) / Constant.CELL_WIDTH;
                    Y = (getRealPos().y) / Constant.CELL_HEIGHT;
                    if (getSeaMap().map[Y][X] != null) {
                        if (getSeaMap().map[Y][X].isIsland() || getSeaMap().map[Y][X].isRubble()) {
                            getSeaMap().items.remove(this);
                            getSeaMap().createExplosion(X, Y);
                        } else if (getSeaMap().map[Y][X].isShip()) {
                            getSeaMap().items.remove(this);
                            getSeaMap().items.remove(getSeaMap().map[Y][X]);
                            getSeaMap().createRubble(X, Y);
                            getSeaMap().createExplosion(X, Y);
                        } else if (getSeaMap().map[Y][X].isWhirl()) {
                            // die
                            getSeaMap().boardControl._Score.SCORE += GetScore();
                            getSeaMap().items.remove(this);
                            getSeaMap().createSplash(X, Y);
                        }
                    } else {
                        getSeaMap().map[Y][X] = this;
                        Shoot(getSeaMap().map);
                    }
                    getSeaMap().busy--;
                } else {
                    Move();
                }
                break;
            case ShipState.Rotating:
                if (FinishRotate()) {
                    State = ShipState.Moving;
                    // SeaMap.Map[Y][X] = null;
                } else {
                    Rotate();
                }
                break;
        }
        setIndex((getIndex() + 1) % getNbOfFrame());
        return true;
    }

    public List<Point> GetDestination(AbstractSprite[][] map, int px, int py, int direction) {
        int x = X;
        int y = Y;
        X = px;
        Y = py;

        List<Point> rs = new ArrayList<Point>();

        int currentDirection = direction;
        int i;
        switch (currentDirection) {
            case 0:
            case 4:
                for (i = 1; i < ViewRange + 1; i++) {
                    if (X + i >= Constant.Width) {
                        rs.add(new Point(X + i - 1, Y));
                        break;
                    }
                    if (map[Y][X + i] != null) {
                        if (map[Y][X + i].isShip()) {
                            rs.add(new Point(X + i, Y));
                            break;
                        }

                        if (map[Y][X + i].isIsland()) {
                            rs.add(new Point(X + i - 1, Y));
                            break;
                        }
                    }
                }
                if (i >= ViewRange + 1) {
                    rs.add(new Point(X + i - 1, Y));
                }

                for (i = 1; i < ViewRange + 1; i++) {
                    if (X - i < 0) {
                        rs.add(new Point(0, Y));
                        break;
                    }
                    if (map[Y][X - i] != null) {
                        if (map[Y][X - i].isShip()) {
                            rs.add(new Point(X - i, Y));
                            break;
                        }

                        if (map[Y][X - i].isIsland()) {
                            rs.add(new Point(X - i + 1, Y));
                            break;
                        }
                    }
                }
                if (i >= ViewRange + 1) {
                    rs.add(new Point(X - i + 1, Y));
                }
                break;
            case 1:
            case 5:
                for (i = 1; i < ViewRange + 1; i++) {
                    if (X + i >= Constant.Width || Y + i >= Constant.Height) {
                        rs.add(new Point(X + i - 1, Y + i - 1));
                        break;
                    }
                    if (map[Y + i][X + i] != null) {
                        if (map[Y + i][X + i].isShip()) {
                            rs.add(new Point(X + i, Y + i));
                            break;
                        }

                        if (map[Y + i][X + i].isIsland()) {
                            rs.add(new Point(X + i - 1, Y + i - 1));
                            break;
                        }
                    }
                }
                if (i >= ViewRange + 1) {
                    rs.add(new Point(X + i - 1, Y + i - 1));
                }

                for (i = 1; i < ViewRange + 1; i++) {
                    if (X - i < 0 || Y - i < 0) {
                        rs.add(new Point(X - i + 1, Y - i + 1));
                        break;
                    }
                    if (map[Y - i][X - i] != null) {
                        if (map[Y - i][X - i].isShip()) {
                            rs.add(new Point(X - i, Y - i));
                            break;
                        }

                        if (map[Y - i][X - i].isIsland()) {
                            rs.add(new Point(X - i + 1, Y - i + 1));
                            break;
                        }
                    }
                }
                if (i >= ViewRange + 1) {
                    rs.add(new Point(X - i + 1, Y - i + 1));
                }
                break;
            case 2:
            case 6:
                for (i = 1; i < ViewRange + 1; i++) {
                    if (Y + i >= Constant.Height) {
                        rs.add(new Point(X, Y + i - 1));
                        break;
                    }
                    if (map[Y + i][X] != null) {
                        if (map[Y + i][X].isShip()) {
                            rs.add(new Point(X, Y + i));
                            break;
                        }

                        if (map[Y + i][X].isIsland()) {
                            rs.add(new Point(X, Y + i - 1));
                            break;
                        }
                    }
                }
                if (i >= ViewRange + 1) {
                    rs.add(new Point(X, Y + i - 1));
                }

                for (i = 1; i < ViewRange + 1; i++) {
                    if (Y - i < 0) {
                        rs.add(new Point(X, Y - i + 1));
                        break;
                    }
                    if (map[Y - i][X] != null) {
                        if (map[Y - i][X].isShip()) {
                            rs.add(new Point(X, Y - i));
                            break;
                        }

                        if (map[Y - i][X].isIsland()) {
                            rs.add(new Point(X, Y - i + 1));
                            break;
                        }
                    }
                }
                if (i >= ViewRange + 1) {
                    rs.add(new Point(X, Y - i + 1));
                }
                break;
            case 3:
            case 7:
                for (i = 1; i < ViewRange + 1; i++) {
                    if (X + i >= Constant.Width || Y - i < 0) {
                        rs.add(new Point(X + i - 1, Y - i + 1));
                        break;
                    }
                    if (map[Y - i][X + i] != null) {
                        if (map[Y - i][X + i].isShip()) {
                            rs.add(new Point(X + i, Y - i));
                            break;
                        }

                        if (map[Y - i][X + i].isIsland()) {
                            rs.add(new Point(X + i - 1, Y - i + 1));
                            break;
                        }
                    }
                }
                if (i >= ViewRange + 1) {
                    rs.add(new Point(X + i - 1, Y - i + 1));
                }

                for (i = 1; i < ViewRange + 1; i++) {
                    if (X - i < 0 || Y + i >= Constant.Height) {
                        rs.add(new Point(X - i + 1, Y + i - 1));
                        break;
                    }
                    if (map[Y + i][X - i] != null) {
                        if (map[Y + i][X - i].isShip()) {
                            rs.add(new Point(X - i, Y + i));
                            break;
                        }

                        if (map[Y + i][X - i].isIsland()) {
                            rs.add(new Point(X - i + 1, Y + i - 1));
                            break;
                        }
                    }
                }
                if (i >= ViewRange + 1) {
                    rs.add(new Point(X - i + 1, Y + i - 1));
                }
                break;
        }
        X = x;
        Y = y;

        return rs;
    }

    public void GetDirection(int targetX, int targetY) {
        int[] cld = { -1, -1, 0, 1, 1, 1, 0, -1 };
        int[] clc = { 0, 1, 1, 1, 0, -1, -1, -1 };
        boolean[][] dd = new boolean[Constant.Height + 2][];
        Point[][] pre = new Point[Constant.Height + 2][];
        for (int i = 0; i < Constant.Height + 2; i++) {
            dd[i] = new boolean[Constant.Width + 2];
            pre[i] = new Point[Constant.Width + 2];
            dd[i][0] = dd[i][Constant.Width + 1] = true;
        }
        for (int i = 1; i < Constant.Height + 1; i++) {
            for (int j = 1; j < Constant.Width + 1; j++) {
                if ((getSeaMap().map[i - 1][j - 1] != null)
                        && (!getSeaMap().map[i - 1][j - 1].isShip()))
                    dd[i][j] = true;
            }
        }
        for (int i = 1; i < Constant.Width + 1; i++) {
            dd[Constant.Height + 1][i] = dd[0][i] = true;
        }

        Point current = new Point(X + 1, Y + 1);
        Point u = current;
        Queue<Point> queue = new Queue<Point>();
        queue.Clear();
        queue.Enqueue(u);

        while (queue.Count() > 0) {
            u = (Point) queue.Dequeue();
            Random r = new Random();
            int random = r.nextInt(2);
            boolean repeat = true;
            int i = random * 7;

            while (repeat) {
                Point v = new Point(u.x + clc[i], u.y + cld[i]);

                if (!dd[v.y][v.x]) {
                    dd[v.y][v.x] = true;
                    pre[v.y][v.x] = u;
                    if (v.x == (targetX + 1) && v.y == (targetY + 1)) {
                        // dung
                        Point k = v;
                        while (!pre[k.y][k.x].equals(current)) {
                            k = pre[k.y][k.x];
                        }
                        int deltaX = k.x - X - 1;
                        int deltaY = k.y - Y - 1;

                        if (deltaX < 0 && deltaY < 0) {
                            DestDirection = 7;
                        }
                        // trai
                        else if (deltaX < 0 && deltaY == 0) {
                            DestDirection = 6;
                        }
                        // trai duoi
                        else if (deltaX < 0 && deltaY > 0) {
                            DestDirection = 5;
                        }
                        // tren
                        else if (deltaX == 0 && deltaY < 0) {
                            DestDirection = 0;
                        }
                        // duoi
                        else if (deltaX == 0 && deltaY > 0) {
                            DestDirection = 4;
                        }
                        // phai tren
                        else if (deltaX > 0 && deltaY < 0) {
                            DestDirection = 1;
                        }
                        // phai
                        else if (deltaX > 0 && deltaY == 0) {
                            DestDirection = 2;
                        }
                        // phai duoi
                        else if (deltaX > 0 && deltaY > 0) {
                            DestDirection = 3;
                        }
                        return;
                    } else {
                        List<Point> targets = GetDestination(getSeaMap().map, v.x - 1, v.y - 1, i);
                        for (int iIndex = 0; iIndex < targets.size(); iIndex++) {
                            Point target = (Point) targets.get(iIndex);
                            if (getSeaMap().map[target.y][target.x] != null
                                    && getSeaMap().map[target.y][target.x]
                                            .equals(getSeaMap().mainShip)
                                    && pre[v.y][v.x] == current) {
                                int deltaX = v.x - X - 1;
                                int deltaY = v.y - Y - 1;

                                if (deltaX < 0 && deltaY < 0) {
                                    DestDirection = 7;
                                }
                                // trai
                                else if (deltaX < 0 && deltaY == 0) {
                                    DestDirection = 6;
                                }
                                // trai duoi
                                else if (deltaX < 0 && deltaY > 0) {
                                    DestDirection = 5;
                                }
                                // tren
                                else if (deltaX == 0 && deltaY < 0) {
                                    DestDirection = 0;
                                }
                                // duoi
                                else if (deltaX == 0 && deltaY > 0) {
                                    DestDirection = 4;
                                }
                                // phai tren
                                else if (deltaX > 0 && deltaY < 0) {
                                    DestDirection = 1;
                                }
                                // phai
                                else if (deltaX > 0 && deltaY == 0) {
                                    DestDirection = 2;
                                }
                                // phai duoi
                                else if (deltaX > 0 && deltaY > 0) {
                                    DestDirection = 3;
                                }
                                return;
                            }
                        }
                        queue.Enqueue(v);
                    }
                }
                if (random == 0) {
                    i++;
                    if (i >= 8) {
                        repeat = false;
                    }
                } else {
                    i--;
                    if (i < 0) {
                        repeat = false;
                    }
                }
            }
        }
    }

    public boolean isEnemy() {
        return true;
    }
}
